package com.shisan.tingshu.search.listener;

import com.shisan.tingshu.search.service.impl.ItemServiceImpl;
import org.redisson.api.RBloomFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;


//@Component 即使加了这个注解，SpringBoot也不会自动扫描到这个Listener类。只能通过 SPI 机制来加载这个Listener类
// SpringApplicationRunListener是SpringBoot提供的一个监听器接口，用于监听SpringBoot应用的启动过程
// 通过实现这个接口，可以在应用启动的不同阶段执行自定义的逻辑，例如在应用上下文准备好后、应用启动前等阶段
public class BloomFilterListener implements SpringApplicationRunListener {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * started()方法在SpringBoot应用启动的过程中被调用，用于监听SpringBoot应用的启动过程
     * 注意：started()方法在SpringBoot应用启动的过程中会被调用两次
     * 第一次是SpringCloud的组件调用的。方法参数ConfigurableApplicationContext，即Spring容器中是没有应用中定义好的Bean对象
     * 第二次是SpringBoot组件调用的。方法参数ConfigurableApplicationContext，即Spring容器中才有应用中定义好的Bean对象
     * @param context   Spring 容器
     * @param timeTaken 启动时间
     */
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        logger.info("BloomFilterListener 被实例化！");  // 如果没有这行日志，说明 SPI 加载失败
        logger.info("当前所有 Bean: {}", Arrays.toString(context.getBeanDefinitionNames()));
        boolean containsBean = context.containsBean("rBloomFilter");
        if (containsBean) { // 当容器中存在布隆过滤器对象时，才进行布隆过滤器的元素同步（避免started()方法在第一次被调用的时候容器中没有布隆过滤器对象而报错）
            // 从Spring容器中获取到布隆过滤器的Bean对象
            RBloomFilter rBloomFilter = context.getBean("rBloomFilter", RBloomFilter.class);
            if (rBloomFilter.count() == 0) { // 如果布隆过滤器元素个数为0，说明布隆过滤器元素还没有同步，需要同步布隆过滤器元素
                // 从Spring容器中获取应用的Bean对象
                ItemServiceImpl itemServiceImpl = context.getBean("itemServiceImpl", ItemServiceImpl.class);
                // 获取数据
                List<Long> albumInfoIdList = itemServiceImpl.getAlbumInfoIdList();
                // 将数据放到布隆过滤器中
                for (Long albumId : albumInfoIdList) {
                    rBloomFilter.add(albumId);
                }
                // 布隆过滤器元素是否同步进去
                logger.info("分布式布隆过滤器的元素个数：" + rBloomFilter.count());
            } else {
                logger.info("布隆过滤器元素已经同步！");
            }
        } else {
            logger.info("容器中不存在布隆过滤器对象");
        }
    }
}